home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / source / xscalebm / xscalebm.asm < prev   
Encoding:
Assembly Source File  |  1994-02-02  |  11.9 KB  |  292 lines

  1. ;-----------------------------------------------------------------------
  2. ; MODULE XSCALEBM
  3. ; This module was written by John Slagel
  4. ; slagel@uxa.cso.uiuc.edu
  5. ;
  6. ; This is some code to do bitmap scaling in VGA Mode X.  It can scale a
  7. ; bitmap of any size down to 2 pixels wide, or up to thousands of pixels
  8. ; wide.  It performs complete clipping, with only a small constant amount
  9. ; of time to clip, no matter how huge the image is.  It draws column by
  10. ; column to reduce the number of plane switches, which are slow. This 
  11. ; code isn't the fastest way to scale, but it works, and I've already
  12. ; posted versions of this to r.g.p a long time ago, so here it is in
  13. ; xlib format. Clips using _LeftClip, _RightClip, _TopClip, _BottomClip.
  14. ; Requires a 386 or better. Really. I use 32-bit registers.
  15. ;
  16. ; Compile with Tasm.
  17. ; C callable like:
  18. ;
  19. ; extern void x_scale_bm(int x,int y,int w, int h,
  20. ;                 int scrnoffs, char far * data );
  21. ;
  22. ; ****** XLIB - Mode X graphics library                ****************
  23. ; ******                                               ****************
  24. ; ****** Written By Themie Gouthas                     ****************
  25. ; ****** Aeronautical Research Laboratory              ****************
  26. ; ****** Defence Science and Technology Organisation   ****************
  27. ; ****** Australia                                     ****************
  28. ;
  29. ; egg@dstos3.dsto.gov.au
  30. ; teg@bart.dsto.gov.au
  31. ;-----------------------------------------------------------------------
  32.  
  33. include xlib.inc
  34.  
  35. .386
  36.  
  37. .code
  38.  
  39.     public _x_scale_bm
  40. _x_scale_bm  proc
  41.  
  42. ARG DestX:word,DestY:word,DestWidth:word,DestHeight:word,ScrnOffs:word,Bitmap:dword
  43. LOCAL SourceWidth:word,SourceHeight:word,SourceOffset:word,SourceWidth2:word,SourceHeight2:word,DestWidth2:word,DestHeight2:word,DecisionX:word,DecisionY:word,ClippedWidth:word,ClippedHeight:word,ByteWidth:word,Plane:byte=LocalStk
  44.  
  45.         push    bp
  46.         mov     bp, sp
  47.         sub     sp, LocalStk                 ; Create space for local variables
  48.         push    si
  49.         push    di
  50.     push     ds
  51.  
  52.     push    ds
  53.     lds    si, [Bitmap]        ; Point DS:SI to bitmap data
  54.     lodsb
  55.     xor     ah, ah            ; Clear ah
  56.     mov    SourceWidth, ax        ; Get bitmap width
  57.     lodsb
  58.     mov    SourceHeight, ax    ; Get bitmap height
  59.     pop    ds
  60.     
  61.     shl    [_LeftClip], 2        ; This clipping code assumes 1 pixel
  62.     shl    [_RightClip], 2        ; granularity
  63.  
  64.     cmp     [DestWidth], 2        ; If destination width is less than 2
  65.     jl      Done            ;     then don't draw it.
  66.  
  67.     cmp     [DestHeight], 2        ; If destination height is less than 2
  68.     jl      Done                    ;     then don't draw it.
  69.  
  70.     mov     ax, [DestY]        ; If it is completely below the
  71.     cmp     ax, [_BottomClip]        ; lower clip bondry,
  72.     jg      Done            ;     then don't draw it.
  73.  
  74.     add     ax, [DestHeight]          ; If it is above clip boundries
  75.     dec     ax                      ;     then don't draw it.
  76.     cmp     ax, [_TopClip]
  77.     jl      Done
  78.  
  79.     mov     ax, [DestX]               ; If it is to the right of the
  80.     cmp     ax, [_RightClip]        ;     then don't draw it.
  81.     jg      Done
  82.  
  83.     add     ax, [DestWidth]        ; If it is completely to the left
  84.     dec     ax            ; of the left clip boundry,
  85.     cmp     ax, [_LeftClip]        ;     then don't draw it.
  86.     jl      Done
  87.  
  88.     mov     ax, [DestWidth]       ; ClippedWidth is initially set to
  89.     mov     [ClippedWidth], ax    ; the requested dest width.
  90.  
  91.     shl     ax, 1               ; Initialize the X decision var
  92.     neg     ax                  ; to be -2*DestHeight
  93.     mov     [DecisionX], ax       ;
  94.  
  95.     mov     ax, [DestHeight]      ; ClippedHeight is initially set to
  96.     mov     [ClippedHeight], ax   ; the requested dest size.
  97.  
  98.     shl     ax, 1               ; Initialize the Y decision var
  99.     neg     ax                  ; to be -2*DestHeight
  100.     mov     [DecisionY], ax       ;
  101.  
  102.     mov    [SourceOffset], 0     ; Offset into source bitmap
  103.  
  104.     movsx   eax, [_TopClip]       ; If Y is below the top
  105.     mov     edx, eax            ; clipping boundry, then we don't
  106.     sub     dx, [DestY]           ; need to clip the top, so we can
  107.     js      NoTopClip           ; jump over the clipping stuff.
  108.  
  109.     mov     [DestY], ax           ; This block performs clipping on the
  110.     sub     [ClippedHeight], dx   ; top of the bitmap.  I have 
  111.     movsx   ecx, [SourceHeight]   ; optimized this block to use only 4
  112.     imul    ecx, edx            ; 32-bit registers, so I'm not even
  113.     mov     eax, ecx            ; gonna try to explain what it's doing.
  114.     mov     edx, 0              ; But I can tell you what results from
  115.     movsx   ebx, [DestHeight]     ; this:  The DecisionY var is updated
  116.     idiv    ebx                 ; to start at the right clipped row.
  117.     movsx   edx, [SourceWidth]    ; Y is moved to the top clip
  118.     imul    edx, eax            ; boundry. ClippedHeight is lowered since
  119.     add    [SourceOffset], dx    ; we won't be drawing all the requested
  120.     imul    eax, ebx            ; rows.  SourceOffset is incremented by
  121.     sub     ecx, eax            ; the number of pixels clipped off the top.
  122.     sub     ecx, ebx            ;
  123.     shl     ecx, 1              ;
  124.     mov     [DecisionY], cx       ; <end of top clipping block >
  125.  
  126. NoTopClip:
  127.     mov     ax, [DestY]           ; If the bitmap doesn't extend over the
  128.     add     ax, [ClippedHeight]   ; bottom clipping boundry, then we
  129.     dec     ax                  ; don't need to clip the bottom, so we
  130.     cmp     ax, [_BottomClip]    ; can jump over the bottom clip code.
  131.     jle     NoBottomClip        ;
  132.  
  133.     mov     ax, [_BottomClip]    ; Clip off the bottom by reducing the
  134.     sub     ax, [DestY]           ; ClippedHeight so that the bitmap won't
  135.     inc     ax                  ; extend over the lower clipping
  136.     mov     [ClippedHeight], ax   ; boundry.
  137.  
  138. NoBottomClip:
  139.     movsx   eax, [_LeftClip]     ; If X is to the left of the
  140.     mov     edx, eax            ; top clipping boundry, then we don't
  141.     sub     dx, [DestX]           ; need to clip the left, so we can
  142.     js      NoLeftClip          ; jump over the clipping stuff.
  143.  
  144.     mov     [DestX], ax           ; This block performs clipping on the
  145.     sub     [ClippedWidth], dx    ; left of the bitmap.  I have 
  146.     movsx   ecx, [SourceWidth]    ; optimized this block to use only 4
  147.     imul    ecx, edx            ; 32-bit registers, so I'm not even
  148.     mov     eax, ecx            ; gonna try to explain what it's doing.
  149.     mov     edx, 0              ; But I can tell you what results from
  150.     movsx   ebx, [DestWidth]      ; this:  The DecisionX var is updated
  151.     idiv    ebx                 ; to start at the right clipped column.
  152.     add     [SourceOffset], ax    ; X is moved to the left clip
  153.     imul    eax, ebx            ; boundry. ClippedWidth is reduced since
  154.     sub     ecx, eax            ; we won't be drawing all the requested
  155.     sub     ecx, ebx            ; cols.  SourceOffset is incremented by
  156.     shl     ecx, 1              ; the number of pixels clipped off the left.
  157.     mov     [DecisionX], cx       ; <end of left clipping block >
  158.  
  159. NoLeftClip:
  160.     mov     ax, [DestX]           ; If the bitmap doesn't extend over the
  161.     add     ax, [ClippedWidth]    ; right clipping boundry, then we
  162.     dec     ax                  ; don't need to clip the right, so we
  163.     cmp     ax, [_RightClip]     ; can jump over the right clip code.
  164.     jle     NoClipRight         ;
  165.  
  166.     mov     ax, [_RightClip]     ; Clip off the right by reducing the
  167.     sub     ax, [DestX]           ; ClippedWidth so that the bitmap won't
  168.     inc     ax                  ; extend over the right clipping
  169.     mov     [ClippedWidth], ax    ; boundry.
  170.  
  171. NoClipRight:
  172.  
  173.     ;Multiply all the widths by 2 to reduce inner loop calculations.
  174.     mov    ax, [SourceWidth]
  175.     shl    ax, 1
  176.     mov    [SourceWidth2], ax
  177.  
  178.     mov    ax, [SourceHeight]
  179.     shl    ax, 1
  180.     mov     [SourceHeight2], ax
  181.  
  182.     mov    ax, [DestWidth]
  183.     shl    ax, 1
  184.     mov    [DestWidth2], ax
  185.  
  186.     mov    ax, [DestHeight]
  187.     shl    ax, 1
  188.     mov    [DestHeight2], ax
  189.  
  190.     mov    ax, [_ScrnLogicalByteWidth]
  191.     mov    [ByteWidth], ax
  192.  
  193.     ;Calculate starting video address
  194.         mov   ax,SCREEN_SEG
  195.         mov   es,ax
  196.         mov   ax,[DestY]                      ; Calculate dest screen row
  197.     mov   bx,[_ScrnLogicalByteWidth]  ;  by mult. dest Y coord by Screen
  198.     mul   bx                          ;  width then adding screen offset
  199.         mov   di,[ScrnOffs]               ;  store result in DI
  200.         add   di,ax
  201.         mov   cx,[DestX]                      ; Load X coord into CX and make a
  202.     mov   dx,cx                       ;  copy in DX
  203.     shr   dx,2                        ; Find starting byte in dest row
  204.     add   di,dx                       ;  add to DI giving screen offset of
  205.                                           ;  first pixel's byte
  206.     
  207.     lds    si, [Bitmap]          ; Point DS:SI to bitmap data
  208.     add    si, 2              ; Skip over width, height
  209.     add    si, [SourceOffset]    ; Skip over clipped off pixels.
  210.  
  211.     mov     dx, SC_INDEX        ; Point the VGA Sequencer to the Map
  212.     mov     al, MAP_MASK        ; Mask register, so that we only need
  213.     out     dx, al              ; to send out 1 byte per column.
  214.     inc     dx                  ; Move to the Sequencer's Data register.
  215.  
  216.     and     cx, 3               ; Calculate the starting plane. This is
  217.     mov     al, 11h             ; just:
  218.     shl     al, cl              ; Plane =  (11h << (X AND 3))
  219.     mov    [Plane], al        ; Save Plane for later
  220.     out     dx, al              ; Select the first plane.
  221.  
  222. ;------------------ NOT SO CRITICAL OUTER LOOP BEGIN ----------------------
  223. RowLoop:
  224.         push    si                  ; Save the starting source index
  225.         push    di                  ; Save the starting dest index
  226.  
  227.         mov     bx, [DecisionY]       ; Make BX be our decision variable
  228.         mov     cx, [ClippedHeight]   ; How many rows to draw
  229.         mov    dx, [ByteWidth]       ; How far to next row
  230.  
  231.         mov     al, ds:[si]         ; Get the first source pixel
  232.  
  233. ;---------------------- CRITICAL INNER LOOP BEGIN --------------------------
  234. ColumnLoop:    
  235.         mov    es:[di], al         ; Draw a pixel
  236.         add     di, dx              ; Go on to the next screen row
  237.         dec     cx                  ; Decrement line counter
  238.         jz      DoneWithCol         ; See if we're done with this column
  239.         add     bx, [SourceHeight2]   ; Increment the decision variable
  240.         js      ColumnLoop          ; Draw this source pixel again
  241.  
  242. IncSourceRow:
  243.         add     si, [SourceWidth]     ; Move to the next source pixel
  244.         sub     bx, [DestHeight2]     ; Decrement the decision variable
  245.         jns     IncSourceRow        ; See if we need to skip another source pixel
  246.         mov     al, ds:[si]         ; Get the next source pixel
  247.         jmp     ColumnLoop          ; Start drawing this pixel
  248.  
  249. ;---------------------- CRITICAL INNER LOOP END --------------------------
  250.  
  251. DoneWithCol:
  252.         pop     di                  ; Restore DI to top row of screen
  253.         pop     si                  ; Restore SI to top row of source bits
  254.  
  255.         rol     [Plane], 1            ; Move to next plane
  256.         adc     di, 0               ; Go on to next screen column
  257.         mov     dx, SC_INDEX        ; Tell the VGA what column we're in
  258.         inc    dx            ; Point to data port
  259.         mov    al, [Plane]        ;
  260.         out     dx, al              ; by updating the map mask register
  261.  
  262.         mov     ax, [SourceWidth2]    ; Increment the X decision variable
  263.         add    [DecisionX], ax        ; Update the X decision variable
  264.         js      NextCol             ; Jump if we're still in the same source col.
  265. IncSourceCol:
  266.         inc     si                  ; Move to next source column
  267.         mov    ax, [DestWidth2]
  268.         sub    [DecisionX], ax        ; Decrement X decision variable
  269.         jns     IncSourceCol        ; See if we skip another source column
  270. NextCol:
  271.         dec     [ClippedWidth]        ; If we're not at last column
  272.         jnz     RowLoop             ;    then do another column
  273.  
  274. ;------------------- NOT SO CRITICAL OUTER LOOP END -------------------------
  275.  
  276. Done:
  277.  
  278.         pop    ds                          ; restore data segment
  279.  
  280.     shr     [_LeftClip], 2                ; Put these back like they were!
  281.     shr    [_RightClip], 2
  282.  
  283.         pop    di                          ; restore registers
  284.         pop    si
  285.         mov    sp, bp                      ; dealloc local variables
  286.         pop    bp
  287.         ret
  288.  
  289. _x_scale_bm  endp
  290.  
  291.     end
  292.